/*
	This file is part of AVRCppLib.

    AVRCppLib is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    AVRCppLib is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with AVRCppLib.  If not, see <http://www.gnu.org/licenses/>.

    Copyright (C) Maxime Lemonnier 2007-2011
 */

#include "../Utils/BitManipulation.h"

#define SIZE_MAX 0xFFFFul // TODO find out why SIZE_MAX from <stdint.h> isn't declared here

template <typename ElementType>
List<ElementType>::List() : begin(NULL), size(0)
{

}

template <typename ElementType>
List<ElementType>::List(const List<ElementType>& rhs) : begin(NULL), size(0)
{
	this->operator =(rhs);
}

template <typename ElementType>
List<ElementType>::~List()
{
	removeAllNodes();
}

template <typename ElementType>
List<ElementType>& List<ElementType>::operator = (const List<ElementType>& rhs)
{
	removeAllNodes();

	size = rhs.size;

	if (isNull(rhs.begin))
		begin = NULL;
	else
	{
		begin = new ListNode(rhs.begin->el);

		ListNode * newNode = begin;
		for (ListNode * temp = rhs.begin->next; !isNull(temp); temp = temp->next )
		{
			newNode->next = new ListNode(temp->el);
			newNode = newNode->next;
			newNode->next = NULL;
		}
		newNode->next = NULL;

	}
	return (*this);
}


template <typename ElementType>
size_t List<ElementType>::numberOfElements() const
{
	return size;
}



template <typename ElementType>
ElementType * List<ElementType>::element(size_t position) const
{
	ListNode * nodeSearched = nodeAt(position);

	if(isNull(nodeSearched))
		return NULL;

	return &(nodeSearched->el);
}


template <typename ElementType>
size_t List<ElementType>::position(const ElementType & element) const
{
	ListNode * nodeSearched = begin;
	size_t positionSearched(0);

	while (!isNull(nodeSearched) && nodeSearched->el != element )
	{
		nodeSearched = nodeSearched->next;
		positionSearched++;
	}

	if (isNull(nodeSearched))
		return -1;

	return positionSearched;
}

template <typename ElementType>
bool List<ElementType>::isEmpty() const
{
	return isNull(begin);
}
template <typename ElementType>
bool List<ElementType>::append(const ElementType & element)
{
	return insertElement(element, numberOfElements());

}

template <typename ElementType>
bool List<ElementType>::insertElement(const ElementType & element, size_t position)
{
	ListNode *  newNode;

	if(position > numberOfElements())
		return false;


	newNode = new ListNode(element);

	if(position == 0)
	{
		newNode->changeNext(begin);
		begin = newNode;
	}
	else
	{
		ListNode *  previousNode = nodeAt(position - 1);

		if(isNull(previousNode))
			return false;

		previousNode->changeNext(newNode);
	}

	size++;
	return true;
}


template <typename ElementType>
bool List<ElementType>::remove(const ElementType & element)
{
	size_t pos = position(element);

	if(pos == SIZE_MAX)
		return false;

	return remove(pos);
}

template <typename ElementType>
bool List<ElementType>::remove(size_t position)
{
	ListNode * nodeSearched;

	if(position > numberOfElements())
		return false;

	if(position == 0)
	{
		nodeSearched = begin;
		if(isNull(nodeSearched))
			return false;
		begin = begin->next;

	}
	else
	{
		ListNode *  nodeSearched = nodeAt(position);

		if(isNull(nodeSearched))
			return false;
	}

	nodeSearched->unlink();
	delete nodeSearched;

	size--;
	return true;
}

template <typename ElementType>
typename List<ElementType>::ListIterator List<ElementType>::elements() const
{
	return ListIterator(begin);
}

template <typename ElementType>
Node<ElementType> * List<ElementType>::nodeAt(size_t position) const
{
	ListNode *  nodeSearched = begin;
	for (size_t previousNodePosition = 0; !isNull(nodeSearched) && previousNodePosition != position; previousNodePosition++)
		nodeSearched = nodeSearched->next;

	return nodeSearched;
}

template <typename ElementType>
void List<ElementType>::removeAllNodes()
{
	ListNode * current = begin;
	while(!isNull(current))
	{
		begin = begin->next;
		delete current;
		current = begin;
	}
	size = 0;
}
